/****************************************************
文件：MBE.cs
作者：UnitySir
邮箱：zouajck@foxmail.com
日期：2021/03/22 20:24:37
功能：Nothing
*****************************************************/

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace DSFramework
{
    /// <summary>
    /// MonoBehaviourExtensions 简称 MBE
    /// </summary>
    public static class MBE
    {
        #region Transform

        /// <summary>
        /// 通过变换获取儿子的组件
        /// </summary>
        /// <param name="trans"></param>
        /// <param name="transName"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T DSGetChildCmpt4Trans<T>(this Transform trans, string transName)
        {
            return trans.Find(transName).GetComponent<T>();
        }

        /// <summary>
        /// 查找子物体
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="childName"></param>
        /// <returns></returns>
        public static GameObject FindChild(this GameObject parent, string childName)
        {
            Transform[] children = parent.GetComponentsInChildren<Transform>();
            bool isFinish = false;
            GameObject child = null;
            foreach (var trans in children)
            {
                if (trans.name.Equals(childName))
                {
                    if (isFinish)
                    {
                        Debug.LogWarning($"在游戏物体{parent}下存在不止一个物体{childName}");
                    }

                    isFinish = true;
                    child = trans.gameObject;
                }
            }

            return child;
        }

        #endregion

        /////////////////////////////////////////////////////////////////////////////////////////////////////////

        #region GameObject

        #region 锚点定位

        public static RectTransform DSetRectTransTop(this GameObject trans, float inset, bool isPiovt = false)
        {
            RectTransform rect = trans.GetOrAddCmpt<RectTransform>();
            if (isPiovt)
            {
                rect.pivot = new Vector2(0.5f, 1);
            }

            Vector2 size = rect.rect.size;

            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, inset, size.y);
            return rect;
        }

        public static RectTransform DSetRectTransBottom(this GameObject trans, float inset, bool isPiovt = false)
        {
            RectTransform rect = trans.GetOrAddCmpt<RectTransform>();
            if (isPiovt)
            {
                rect.pivot = new Vector2(0.5f, 0);
            }

            Vector2 size = rect.rect.size;

            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Bottom, inset, size.y);
            return rect;
        }

        public static RectTransform DSetRectTransLeft(this GameObject trans, float inset, bool isPiovt = false)
        {
            RectTransform rect = trans.GetOrAddCmpt<RectTransform>();
            if (isPiovt)
            {
                rect.pivot = new Vector2(0, 0.5f);
            }

            Vector2 size = rect.rect.size;

            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, inset, size.x);
            return rect;
        }

        public static RectTransform DSetRectTransRight(this GameObject trans, float inset, bool isPiovt = false)
        {
            RectTransform rect = trans.GetOrAddCmpt<RectTransform>();
            if (isPiovt)
            {
                rect.pivot = new Vector2(1, 0.5f);
            }

            Vector2 size = rect.rect.size;

            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Right, inset, size.x);
            return rect;
        }


        /// <summary>
        /// 相对于左下角
        /// </summary>
        /// <param name="trans"></param>
        /// <param name="left"></param>
        /// <param name="bottom"></param>
        /// <returns></returns>
        public static RectTransform DSetRectTransLeftBottom(this GameObject trans, float width, float height,
            float inset1, float inset2, bool isPiovt = false)
        {
            RectTransform rect = trans.GetOrAddCmpt<RectTransform>();
            if (isPiovt)
            {
                rect.pivot = new Vector2(0, 0);
            }

            rect.sizeDelta = new Vector2(width, height);
            Vector2 size = rect.rect.size;
            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Bottom, inset1, size.x);
            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, inset2, size.y);
            return rect;
        }

        public static RectTransform DSetRectTransLeftBottom(this GameObject trans,
            float inset1, float inset2, bool isPiovt = false)
        {
            RectTransform rect = trans.GetOrAddCmpt<RectTransform>();
            if (isPiovt)
            {
                rect.pivot = new Vector2(0, 0);
            }

            Vector2 size = rect.rect.size;
            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Bottom, inset1, size.x);
            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, inset2, size.y);
            return rect;
        }


        /// <summary>
        /// 相对于左上角
        /// </summary>
        /// <param name="trans"></param>
        /// <param name="width">对象宽</param>
        /// <param name="height">对象高</param>
        /// <param name="inset1"></param>
        /// <param name="inset2"></param>
        /// <param name="isPiovt">是否改变锚点</param>
        /// <returns></returns>
        public static RectTransform DSetRectTransLeftTop(this GameObject trans, float width, float height, float inset1,
            float inset2, bool isPiovt = false)
        {
            RectTransform rect = trans.GetOrAddCmpt<RectTransform>();
            if (isPiovt)
            {
                rect.pivot = new Vector2(0, 1);
            }

            rect.sizeDelta = new Vector2(width, height);

            Vector2 size = rect.rect.size;


            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, inset1, size.x);
            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, inset2, size.y);

            return rect;
        }

        public static RectTransform DSetRectTransLeftTop(this GameObject trans, float inset1,
            float inset2, bool isPiovt = false)
        {
            RectTransform rect = trans.GetOrAddCmpt<RectTransform>();
            if (isPiovt)
            {
                rect.pivot = new Vector2(0, 1);
            }

            Vector2 size = rect.rect.size;


            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, inset1, size.x);
            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, inset2, size.y);

            return rect;
        }

        /// <summary>
        /// 相对于右下角
        /// </summary>
        /// <param name="trans"></param>
        /// <param name="index1"></param>
        /// <param name="index2"></param>
        /// <returns></returns>
        public static RectTransform DSetRectTransRightBottom(this GameObject trans, float width, float height,
            float inset1, float inset2, bool isPiovt = false)
        {
            RectTransform rect = trans.GetOrAddCmpt<RectTransform>();
            if (isPiovt)
            {
                rect.pivot = new Vector2(1, 0);
            }

            rect.sizeDelta = new Vector2(width, height);

            Vector2 size = rect.rect.size;


            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Right, inset1, size.x);
            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Bottom, inset2, size.y);

            return rect;
        }

        public static RectTransform DSetRectTransRightBottom(this GameObject trans,
            float inset1, float inset2, bool isPiovt = false)
        {
            RectTransform rect = trans.GetOrAddCmpt<RectTransform>();
            if (isPiovt)
            {
                rect.pivot = new Vector2(1, 0);
            }

            Vector2 size = rect.rect.size;


            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Right, inset1, size.x);
            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Bottom, inset2, size.y);

            return rect;
        }

        public static void DSetRectTransRightBottom(this RectTransform rect, float width, float height,
            float inset1, float inset2, bool isPiovt = false)
        {
            if (isPiovt)
            {
                rect.pivot = new Vector2(1, 0);
            }

            rect.sizeDelta = new Vector2(width, height);

            Vector2 size = rect.rect.size;

            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Right, inset1, size.x);
            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Bottom, inset2, size.y);
        }

        /// <summary>
        /// 相对于右上角
        /// </summary>
        /// <param name="trans"></param>
        /// <param name="index1"></param>
        /// <param name="index2"></param>
        /// <returns></returns>
        public static RectTransform DSetRectTransRightTop(this GameObject trans, float width, float height,
            float inset1, float inset2, bool isPiovt = false)
        {
            RectTransform rect = trans.GetOrAddCmpt<RectTransform>();
            if (isPiovt)
            {
                rect.pivot = new Vector2(1, 1);
            }

            rect.sizeDelta = new Vector2(width, height);

            Vector2 size = rect.rect.size;

            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, inset1, size.x);
            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Right, inset2, size.y);

            return rect;
        }

        public static RectTransform DSetRectTransRightTop(this GameObject trans,
            float inset1, float inset2, bool isPiovt = false)
        {
            RectTransform rect = trans.GetOrAddCmpt<RectTransform>();
            if (isPiovt)
            {
                rect.pivot = new Vector2(1, 1);
            }

            Vector2 size = rect.rect.size;

            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, inset1, size.x);
            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Right, inset2, size.y);

            return rect;
        }

        /// <summary>
        /// 相对于中心点
        /// </summary>
        /// <param name="rt"></param>
        /// <param name="offsetX"></param>
        /// <param name="offsetY"></param>
        public static RectTransform DSetRectTransCenter(this GameObject trans, float offsetX, float offsetY)
        {
            RectTransform rect = trans.GetOrAddCmpt<RectTransform>();
            Vector2 size = rect.rect.size;
            rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x);
            rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.y);
            rect.localPosition = new Vector2(offsetX, offsetY);
            return rect;
        }

        /// <summary>
        /// 让对象充满父类
        /// </summary>
        /// <param name="trans"></param>
        public static RectTransform DSetRectTransFull(this GameObject trans)
        {
            RectTransform rect = trans.GetOrAddCmpt<RectTransform>();

            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, 0, 0);
            rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 0, 0);
            rect.anchorMin = Vector2.zero;
            rect.anchorMax = Vector2.one;
            rect.pivot = new Vector2(0.5f, 0.5f);
            return rect;
        }

        #endregion

        public static T GetCmpt4Tag<T>(string tagName) where T : Component
        {
            return GameObject.FindWithTag(tagName).GetOrAddCmpt<T>();
        }

        public static Transform GetTrans4Tag(string tagName)
        {
            return GameObject.FindWithTag(tagName).transform;
        }

        public static Transform GetGameObj4Tag(string tagName)
        {
            return GameObject.FindWithTag(tagName).transform;
        }

        public static Transform GetGameObj4Name(string objName)
        {
            return GameObject.Find(objName).transform;
        }

        public static T GetCmpt4Name<T>(string objName) where T : Component
        {
            return GameObject.Find(objName).GetOrAddCmpt<T>();
        }

        public static Vector3 Pos(this GameObject obj)
        {
            return obj.transform.position;
        }

        public static Vector3 Pos(this Transform obj)
        {
            return obj.position;
        }

        public static Vector3 LocalPos(this GameObject obj)
        {
            return obj.transform.localPosition;
        }

        public static Vector3 LocalPos(this Transform obj)
        {
            return obj.localPosition;
        }

        public static GameObject LocalPos(this GameObject obj, Vector3 pos)
        {
            obj.transform.localPosition = pos;
            return obj;
        }

        public static Transform LocalPos(this Transform obj, Vector3 pos)
        {
            obj.localPosition = pos;
            return obj;
        }

        public static GameObject LocalPosX(this GameObject obj, float x)
        {
            var localPosition = obj.transform.localPosition;
            localPosition = new Vector3(x, localPosition.y, localPosition.z);
            obj.transform.localPosition = localPosition;
            return obj;
        }

        public static GameObject LocalPosY(this GameObject obj, float y)
        {
            var localPosition = obj.transform.localPosition;
            localPosition = new Vector3(localPosition.x, y, localPosition.z);
            obj.transform.localPosition = localPosition;
            return obj;
        }

        public static GameObject LocalPosZ(this GameObject obj, float z)
        {
            var localPosition = obj.transform.localPosition;
            localPosition = new Vector3(localPosition.x, localPosition.y, z);
            obj.transform.localPosition = localPosition;
            return obj;
        }

        public static Transform LocalPosZ(this Transform trans, float z)
        {
            var localPosition = trans.localPosition;
            localPosition = new Vector3(localPosition.x, localPosition.y, z);
            trans.localPosition = localPosition;
            return trans;
        }

        public static GameObject PosX(this GameObject obj, float x)
        {
            var position = obj.transform.position;
            position = new Vector3(x, position.y, position.z);
            obj.transform.position = position;
            return obj;
        }

        public static GameObject PosY(this GameObject obj, float y)
        {
            var position = obj.transform.position;
            position = new Vector3(position.x, y, position.z);
            obj.transform.position = position;
            return obj;
        }

        public static GameObject PosZ(this GameObject obj, float z)
        {
            var position = obj.transform.position;
            position = new Vector3(position.x, position.y, z);
            obj.transform.position = position;
            return obj;
        }

        public static GameObject Pos(this GameObject obj, Vector3 pos)
        {
            obj.transform.position = pos;
            return obj;
        }

        public static GameObject RectPos(this GameObject obj, Vector3 pos)
        {
            var rect = obj.GetComponent<RectTransform>();
            rect.anchoredPosition = pos;
            return obj;
        }

        public static Transform RectPos(this Transform obj, Vector3 pos)
        {
            var rect = obj.GetComponent<RectTransform>();
            rect.anchoredPosition = pos;
            return obj;
        }

        public static Transform Pos(this Transform obj, Vector3 pos)
        {
            obj.position = pos;
            return obj;
        }

        public static GameObject SetParent(this GameObject obj, GameObject o)
        {
            obj.transform.SetParent(o.transform, false);
            return obj;
        }

        public static GameObject SetParent(this GameObject obj, Transform o, bool isWorld = false)
        {
            obj.transform.SetParent(o, isWorld);
            return obj;
        }

        public static void ReSetLocalPos(this GameObject obj)
        {
            obj.transform.localPosition = Vector3.zero;
        }

        public static void ReSetLocalPos(this Transform obj)
        {
            obj.localPosition = Vector3.zero;
        }

        public static void ReSetLocalScale(this GameObject obj)
        {
            obj.transform.localScale = Vector3.one;
        }

        public static void ReSetLocalEulerAngles(this GameObject obj)
        {
            obj.transform.localEulerAngles = Vector3.zero;
        }

        public static void ReSetLocalEulerAngles(this Transform obj)
        {
            obj.localEulerAngles = Vector3.zero;
        }

        public static void Show(this GameObject obj)
        {
            if (!obj.activeSelf)
                obj.SetActive(true);
        }

        public static void Hide(this GameObject obj)
        {
            if (obj.activeSelf)
                obj.SetActive(false);
        }

        public static void Show(this Transform obj)
        {
            if (!obj.gameObject.activeSelf)
                obj.gameObject.SetActive(true);
        }

        public static void Hide(this Transform obj)
        {
            if (obj.gameObject.activeSelf)
                obj.gameObject.SetActive(false);
        }

        public static void Destroy(this GameObject obj)
        { 
            Object.Destroy(obj);
        }

        public static void Destroy(this Transform obj)
        {
            Object.Destroy(obj);
        }

        public static void LookAt(this GameObject obj, Vector3 worldPos)
        {
            obj.transform.LookAt(worldPos);
        }

        public static void LookAt(this GameObject obj, Transform trans)
        {
            obj.transform.LookAt(trans);
        }

        public static T GetCmpt<T>(this Transform transform) where T : Component
        {
            return transform.GetOrAddCmpt<T>();
        }

        public static T GetCmpt<T>(this GameObject transform) where T : Component
        {
            return transform.GetOrAddCmpt<T>();
        }

        public static T GetChildCmpt<T>(this GameObject obj, int index) where T : Component
        {
            return obj.transform.GetChild(index).GetCmpt<T>();
        }

        public static T GetChildCmpt<T>(this Transform obj, int index) where T : Component
        {
            return obj.GetChild(index).GetCmpt<T>();
        }

        public static T GetOrAddCmpt<T>(this GameObject go) where T : Component
        {
            T t = go.GetComponent<T>();
            if (t == null)
            {
                t = go.AddComponent<T>();
            }

            return t;
        }

        public static T GetOrAddCmpt<T>(this Transform go) where T : Component
        {
            T t = go.GetComponent<T>();
            if (t == null)
            {
                t = go.gameObject.AddComponent<T>();
            }

            return t;
        }

        #region 物体跟随鼠标移动

        /// <summary>
        /// 将 UI 移动到指定物体的坐标
        /// </summary>
        /// <param name="canvas">画布</param>
        /// <param name="wordCamera">世界相机</param>
        /// <param name="pos">需要移动到的位置</param>
        /// <param name="needMvUI">需要移动的UI</param>
        public static void WordToViewportPoint(RectTransform canvas, Camera wordCamera, Vector3 pos, RectTransform needMvUI)
        {
            Vector2 canvasSize = canvas.sizeDelta;
            Vector3 viewPortPos3d = wordCamera.WorldToViewportPoint(pos);
            Vector2 viewPortRelative = new Vector2(viewPortPos3d.x - 0.5f, viewPortPos3d.y - 0.5f);
            Vector2 cubeScreenPos = new Vector2(viewPortRelative.x * canvasSize.x, viewPortRelative.y * canvasSize.y);

            needMvUI.anchoredPosition = cubeScreenPos;
        }

        /// <summary>
        /// 物体跟随鼠标移动
        /// </summary>
        /// <param name="m_obj">需要移动的对象</param>
        /// <param name="camera">相机</param>
        /// <returns></returns>
        public static Vector3 FromMouseMove(this GameObject m_obj, Camera camera)
        {
            Vector3 screenPos = camera.WorldToScreenPoint(m_obj.transform.position);
            Vector3 mousePos = Input.mousePosition;
            mousePos.z = screenPos.z;
            Vector3 worldPos = camera.ScreenToWorldPoint(mousePos);
            //m_obj.transform.position = worldPos;
            return worldPos;
        }

        /// <summary>
        /// 物体跟随鼠标移动
        /// </summary>
        /// <param name="m_obj">需要移动的对象</param>
        /// <param name="camera">相机</param>
        /// <returns></returns>
        public static Vector3 FromMouseMove(this Transform m_obj, Camera camera)
        {
            Vector3 screenPos = camera.WorldToScreenPoint(m_obj.position);
            Vector3 mousePos = Input.mousePosition;
            mousePos.z = screenPos.z;
            Vector3 worldPos = camera.ScreenToWorldPoint(mousePos);
            //m_obj.position = worldPos;
            return worldPos;
        }

        #endregion

        #endregion
    }
}